package httpproxy.client;

import httpproxy.util.IProxyClientThreadListener;

import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//import java.io.B

import javax.swing.event.EventListenerList;

public class ProxyClientThread extends Thread 
{
	private EventListenerList evenLstList = new EventListenerList();;
	
	private static final int MAX_BUFFER_LENGTH = 256;
	private Socket clientSocket;
	private InputStream clientInputStream;
	private OutputStream clientOutputStream;
	
	private boolean _isChainProxy = false;
	private String _chainProxyHost = "";
	private InetAddress _chainProxyAddress;
	private int _chainProxyPort = 0;
	
	private Queue<HttpRequest> requests = new LinkedList<HttpRequest>();
	private boolean running = true;
	
	public ProxyClientThread()
	{
	}
	
	public ProxyClientThread(Socket sk)
	{
		clientSocket = sk;
		try{
			clientInputStream = clientSocket.getInputStream();
			clientOutputStream = clientSocket.getOutputStream();
		}catch(IOException ex)
		{
			//UnsupportedEncodingException
			ex.printStackTrace();
		}
	}
	
	public ProxyClientThread(Socket sk, String chainproxyHost, int chainPort)
	{
		clientSocket = sk;
		_isChainProxy = true;
		_chainProxyHost = chainproxyHost;
		_chainProxyPort = chainPort;
		
		try{
			
			Pattern chain_host_pattern = Pattern.compile("([0-9]{1,3}[\\.]){3}[0-9]{1,3}");
			Matcher chain_host_matcher = chain_host_pattern.matcher(_chainProxyHost);
			_chainProxyAddress = InetAddress.getByName(_chainProxyHost);
			if(chain_host_matcher.find())
			{
				String[] sb = _chainProxyHost.split("\\.");
				//System.out.println(_chainProxyHost + " - " + sb.length);
				byte[] addr = new byte[]{(byte)Integer.parseInt(sb[0]), (byte)Integer.parseInt(sb[1]), (byte)Integer.parseInt(sb[2]), (byte)Integer.parseInt(sb[3])};
				_chainProxyAddress = InetAddress.getByAddress(addr);
			}
			
			clientInputStream = clientSocket.getInputStream();
			clientOutputStream = clientSocket.getOutputStream();
			
		}catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
	
	public void addProxyClientListener(IProxyClientThreadListener lster)
	{
		evenLstList.add(IProxyClientThreadListener.class, lster);
	}
	
	public void removeProxyClientListener(IProxyClientThreadListener lster)
	{
		evenLstList.remove(IProxyClientThreadListener.class, lster);
	}
	
	private void fireThreadDone()
	{
		System.out.println("[ProxyClientThread] Chuan bi dong Client socket.");
		
		Object[] listeners = evenLstList.getListenerList();
	    // loop through each listener and pass on the event if needed
	    int numListeners = listeners.length;
	    for (int i = 0; i<numListeners - 1; i+=2)
	    {
	    	if (listeners[i] == IProxyClientThreadListener.class) 
	        {
	    		// pass the event to the listeners event dispatch method
	        	((IProxyClientThreadListener)listeners[i+1]).onClientDone(clientSocket);
	        }           
	    }
	}
	
	public HttpRequest createHttpRequest(int rCount)
	{
			if(_isChainProxy)
				return (new HttpRequest(String.format("%d - %d", Thread.currentThread().getId(), rCount), _chainProxyAddress, _chainProxyPort));
			
			return (new HttpRequest(String.format("%d - %d", Thread.currentThread().getId(), rCount)));
	}
	
	int requestCount = 0;
	@Override
	public void run()
	{
		HttpRequest request = createHttpRequest(requestCount++);
		HttpResponse response = new HttpResponse(String.format("R%d", currentThread().getId()));
		int count;
		byte[] buff = new byte[MAX_BUFFER_LENGTH];
		try{
			//Doc request header tu client
			request.parse(clientInputStream);
			
			//Gui request header
			request.sendRequestHeaderString();
			
			response.setFromHost(request.getHost());
			
			//Doc/Gui post data
			if(request.getMethod().equals("POST"))
			{
				byte[] content = new byte[request.getContentLength()];
				
				if ( (count=clientInputStream.read(content)) > -1) 
				{	
					//System.out.print(new String(content, 0, count));
					request.getServerOutputStream().write(content, 0, count);    
		        }
				request.getServerOutputStream().flush();
			}
			
			//doc response header tu server
			response.readResponseHeader(request.getServerInputStream());
			
			//gui response header den client
			response.sendResponseHeader(clientOutputStream);
			
			//doc va gui respone data
			if(response.isDenied())
			{
				//Neu bi chan
				clientOutputStream.write(response.getContentData(), 0, response.getContentLength());
				clientOutputStream.flush();
			}
			else
			{
				InputStream  in  = request.getServerInputStream();
				int byteread = 0;
				while (-1 < ( count  = in.read(buff))) 
				{
					clientOutputStream.write(buff,0,count);
					clientOutputStream.flush();
					byteread += count;
					
					Thread.yield();
					
					if(byteread == response.getContentLength())
						break;
				}
			}
			
			//Hoan tat viec tra ket qua cho client.
			//Thong bao cho server dong socket nay lai va ket thuc
			try{
				request.getWebServerSocket().close();
				clientSocket.close();
			}catch(IOException ex){}
			
			//fireThreadDone();
			
		}catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
}